package util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xalan.internal.xsltc.trax.DOM2SAX;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.SAXException;
import play.Play;
import play.mvc.Http;
import scala.xml.Node;
import scala.xml.parsing.NoBindingFactoryAdapter;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class Common {

    public static boolean isEqualString(String a, String b) {
        if (a == null && b == null) {
            return true;
        }
        if (a == null || b == null) {
            return false;
        }
        return a.trim().equals(b.trim());
    }

    /**
     * 从XML转换过来的JSON中取出某个值
     * TODO: JSON中值为列表类型, JSONArray类型
     */
    public static Object getValueFromXmlJson(JSONObject jsonObject, Class type, String key) {
        if (!jsonObject.containsKey(key)) {
            return null;
        }
        Object valObj = jsonObject.get(key);
        if (valObj == null) {
            return null;
        }
        if (valObj instanceof List) {
            if (((List) valObj).size() > 0) {
                valObj = ((List) valObj).get(0);
                if (type == String.class) {
                    return valObj.toString();
                } else if (type == Integer.class || type == int.class) {
                    return Integer.valueOf(valObj.toString());
                } else if (type == Long.class || type == long.class) {
                    return Long.valueOf(valObj.toString());
                } else if (type == Float.class || type == float.class) {
                    return Float.valueOf(valObj.toString());
                } else if (type == Double.class || type == double.class) {
                    return Double.valueOf(valObj.toString());
                }
                return valObj.toString();
            } else {
                return null;
            }
        } else if (valObj instanceof JSONObject) {
            try {
                Object subVal = type.newInstance();
                putXmlParsedJsonToObject(subVal, (JSONObject) valObj);
                return subVal;
            } catch (InstantiationException e) {
                e.printStackTrace();
                return null;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                return null;
            }
        } else {
            if (type == String.class) {
                return valObj.toString();
            } else if (type == Integer.class || type == int.class) {
                return Integer.valueOf(valObj.toString());
            } else if (type == Long.class || type == long.class) {
                return Long.valueOf(valObj.toString());
            } else if (type == Float.class || type == float.class) {
                return Float.valueOf(valObj.toString());
            } else if (type == Double.class || type == double.class) {
                return Double.valueOf(valObj.toString());
            }
            return valObj.toString();
        }
    }

    /**
     * 把从XML转换过来的JSON的内容放入Java对象中
     */
    public static void putXmlParsedJsonToObject(Object obj, JSONObject jsonObject) {
        List<Field> fields = getFields(obj);
        for (Field field : fields) {
            Class fieldType = field.getType();
            Object val = getValueFromXmlJson(jsonObject, fieldType, field.getName());
            if (val != null) {
                Common.setPropertyOfObject(obj, field.getName(), val);
            }
        }
    }

    public static Node w3cDocumentToScalaNode(org.w3c.dom.Document doc) throws IOException, SAXException {
        DOM2SAX dom2sax = new DOM2SAX(doc);
        NoBindingFactoryAdapter adapter = new NoBindingFactoryAdapter();
        dom2sax.setContentHandler(adapter);
        dom2sax.parse();
        return adapter.rootElem();
    }

    public static String encode(String algorithm, String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文转换成十六进制的字符串形式
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }


    public static String sha1(String s) {
        if (s == null) {
            return null;
        }
        return encode("SHA1", s);
    }

    public static boolean isEmptyString(String s) {
        return s == null || s.trim().length() < 1;
    }

    public static String randomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static String randomStringForNum(int length) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }


    public static String md5(String str) {
        try {
            byte[] bytesOfMessage = str.getBytes("UTF-8");
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] thedigest = md.digest(bytesOfMessage);
            return new String(thedigest, Charset.forName("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            return str;
        } catch (UnsupportedEncodingException e2) {
            return str;
        }
    }

    public static String base64encode(String str) {
        try {
            return new String(Base64.encodeBase64(str.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getStringConfig(String key) {
        return Play.application().configuration().getString(key);
    }

    public static String getStringConfig(String key, String defaultValue) {
        return Play.application().configuration().getString(key, defaultValue);
    }

    public static boolean getBooleanConfig(String key) {
        return Play.application().configuration().getBoolean(key);
    }

    public static int getIntConfig(String key) {
        return getIntConfig(key, 0);
    }

    public static int getIntConfig(String key, int defaultValue) {
        play.Configuration configuration = Play.application().configuration();
        if (!configuration.keys().contains(key)) {
            return defaultValue;
        }
        return Play.application().configuration().getInt(key);
    }

    public static Object getStaticProperty(Class cls, String name) {
        try {
            Field field = cls.getDeclaredField(name);
            field.setAccessible(true);
            return field.get(null);
        } catch (NoSuchFieldException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    public static Integer[] parseIntArray(int[] array) {
        Integer[] result = new Integer[array.length];
        for (int i = 0; i < array.length; ++i) {
            result[i] = array[i];
        }
        return result;
    }

    public static List<Integer> parseIntArrayToList(int[] array) {
        List<Integer> result = new ArrayList<Integer>();
        for (int item : array) {
            result.add(item);
        }
        return result;
    }

    public static String getSSOBaseUrl() {
        return getStringConfig("auth.sso_base_url ");
    }

    public static <T> String parseSetToJsonString(Set<T> set) {
        JSONArray jsonArray = new JSONArray();
        for (Object val : set) {
            jsonArray.add(val);
        }
        return jsonArray.toJSONString();
    }

    public static <T> Set<T> parseJsonStringToSet(String jsonStr) {
        JSONArray jsonArray = JSON.parseArray(jsonStr);
        Set<T> set = new HashSet<T>();
        for (int i = 0; i < jsonArray.size(); ++i) {
            set.add((T) jsonArray.get(i));
        }
        return set;
    }

    public static String joinIntString(String sep, int[] values) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < values.length; ++i) {
            if (i > 0) {
                builder.append(sep);
            }
            builder.append("" + values[i]);
        }
        return builder.toString();
    }

    public static void setPropertyOfObject(Object obj, String name, Object val) {
        Class cls = obj.getClass();
        Field field = null;
        try {
            field = cls.getField(name);
            field.setAccessible(true);
            field.set(obj, val);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static Object getStaticPropertyOfClass(Class cls, String name) {
        try {
            Field field = cls.getDeclaredField(name);
            field.setAccessible(true);
            return field.get(cls);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object getStaticPropertyOfObject(Object obj, String name) {
        return getStaticPropertyOfClass(obj.getClass(), name);
    }

    /**
     * 获取对象的名为name的属性，使用反射。如果不存在，则返回null
     */
    public static Object getPropertyOfObject(Object obj, String name) {
        if (obj == null) {
            return null;
        }
        Class cls = obj.getClass();
        try {
            Field field = cls.getField(name);
            field.setAccessible(true);
            return field.get(obj);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取对象的字段列表
     */
    public static List<String> getFieldNames(Object obj) {
        if (obj == null) {
            return null;
        }
        Class cls = obj.getClass();
        List<String> result = new ArrayList<String>();
        for (Field field : cls.getFields()) {
            result.add(field.getName());
        }
        return result;
    }

    public static List<Field> getFields(Object obj) {
        if (obj == null) {
            return null;
        }
        Class cls = obj.getClass();
        List<Field> result = new ArrayList<Field>();
        for (Field field : cls.getFields()) {
            result.add(field);
        }
        return result;
    }

    public static boolean checkObjectContainsProperty(Object obj, String name) {
        Class cls = obj.getClass();
        try {
            cls.getField(name);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }

    /**
     * 把字符串source的超过长度maxLength的部分缩略为pendingStr，并且pendingStr本身也是占位置的
     * 比如，把HelloWorld缩略为Hel...
     */
    public static String shortenToSummary(String source, int maxLength, String pendingStr) {
        int maxRemainingLen = maxLength - pendingStr.length();
        int sourceLen = source.length();
        if (sourceLen < maxLength) {
            return source;
        }
        return source.substring(0, maxRemainingLen) + pendingStr;
    }

    public static boolean inArray(int val, int[] array) {
        for (int item : array) {
            if (item == val) {
                return true;
            }
        }
        return false;
    }

    public static byte[] fullyReadStreamToBytes(InputStream inputStream) throws IOException {
        if (inputStream == null) {
            return null;
        }
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[8092];
        while (inputStream.available() > 0) {
            int size = inputStream.read(bytes);
            byteArrayOutputStream.write(bytes, 0, size);
        }
        bytes = byteArrayOutputStream.toByteArray();
        byteArrayOutputStream.close();
        return bytes;
    }


    public static String fullyReadStream(InputStream inputStream) throws IOException {
        byte[] bytes = fullyReadStreamToBytes(inputStream);
        if (bytes == null) {
            return null;
        }
        return new String(bytes, "UTF-8");
    }

    public static InputStream createInputStreamFromString(String str) throws UnsupportedEncodingException {
        return createInputStreamFromString(str, "UTF-8");
    }

    public static InputStream createInputStreamFromString(String str, String encoding) throws UnsupportedEncodingException {
        return new ByteArrayInputStream(str.getBytes(encoding));
    }

    public static String utf8ToGBK(String str) {
        if (str == null) {
            return null;
        }
        try {
            byte[] bytes = str.getBytes("UTF-8");
            return new String(bytes, "GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return str;
        }
    }


    public static Boolean isPhone(Http.Request request) {
        boolean isMoblie = false;
        String[] mobileAgents = {"iphone", "android", "phone", "mobile", "wap", "netfront", "java", "opera mobi",
                "opera mini", "ucweb", "windows ce", "symbian", "Googlebot-Mobile"};
        if (!isPadVisit(request)) {
            if (request.getHeader("User-Agent") != null) {
                for (String mobileAgent : mobileAgents) {
                    if (request.getHeader("User-Agent").toLowerCase().indexOf(mobileAgent) >= 0) {
                        isMoblie = true;
                        break;
                    }
                }
            }
        }
        return isMoblie;
    }

    public static Boolean isPhoneVisit(Http.Request request) {
        boolean isMoblie = false;
        String[] mobileAgents = {"iphone", "android", "phone", "mobile", "wap", "netfront", "java", "opera mobi",
                "opera mini", "ucweb", "windows ce", "symbian", "Googlebot-Mobile"};
        if (!isPadVisit(request)) {
            if (request.getHeader("User-Agent") != null) {
                for (String mobileAgent : mobileAgents) {
                    if (request.getHeader("User-Agent").toLowerCase().indexOf(mobileAgent) >= 0) {
                        isMoblie = true;
                        break;
                    }
                }
            }
        }
        return isMoblie;
    }


    public static Boolean isWeixinVisit(Http.Request request) {
        boolean isWeixin = false;
        if (request.getHeader("User-Agent") != null) {
            if (request.getHeader("User-Agent").toLowerCase().indexOf("micromessenger") >= 0) {
                isWeixin = true;
            }
        }
        return isWeixin;
    }

    public static Boolean isIeVisit(Http.Request request) {
        boolean isIE = false;
        if (request.getHeader("User-Agent") != null) {
            if (request.getHeader("User-Agent").toLowerCase().indexOf("msie") >= 0) {
                isIE = true;
            }
        }
        return isIE;
    }

    public static Boolean isIeVisitLess8(Http.Request request) {
        boolean isIE = false;
        if (request.getHeader("User-Agent") != null) {
            if (request.getHeader("User-Agent").toLowerCase().indexOf("msie 8.0") >= 0
                    || request.getHeader("User-Agent").toLowerCase().indexOf("msie 7.0") >= 0
                    || request.getHeader("User-Agent").toLowerCase().indexOf("msie 6.0") >= 0
                    || request.getHeader("User-Agent").toLowerCase().indexOf("msie 5.0") >= 0
                    ) {
                isIE = true;
            }
        }
        return isIE;
    }

    public static Boolean isPadVisit(Http.Request request) {
        boolean isPad = false;
        if (request.getHeader("User-Agent") != null) {
            if (request.getHeader("User-Agent").toLowerCase().indexOf("pad") >= 0) {
                isPad = true;
            }
        }
        return isPad;
    }

    public static Boolean isIphoneVisit(Http.Request request) {
        boolean isIphone = false;
        if (request.getHeader("User-Agent") != null) {
            if (request.getHeader("User-Agent").toLowerCase().indexOf("iphone") >= 0) {
                isIphone = true;
            }
        }
        return isIphone;
    }


    public static String getRemortIP(Http.Request request) {
        if (request.getHeader("x-forwarded-for") == null) {
            return request.remoteAddress();
        }
        return request.getHeader("x-forwarded-for");
    }

    public static String getFileUnderCurrentDirectory(String path) {
        File file = new File(path);
        return file.getAbsolutePath();
    }

    public static InputStream getResource(String path) {
        return Play.application().classloader().getResourceAsStream(path);
    }


    //小数点两位
    public static double CorrectToTwoDecimalPlaces(double num) {
        BigDecimal b = new BigDecimal(num);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /*
    *过滤emoji表情
    * 因为mysql utf-8是三位，而表情为四位
    *
    *
    * */
    public static String FilterEmoji(String source) {
        if (!ContainsEmoji(source)) {
            return source;//如果不包含，直接返回
        }
        //到这里铁定包含
        StringBuilder buf = null;

        int len = source.length();

        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (IsEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }

                buf.append(codePoint);
            } else {
            }
        }

        if (buf == null) {
            return source;//如果没有找到 emoji表情，则返回源字符串
        } else {
            if (buf.length() == len) {//这里的意义在于尽可能少的toString，因为会重新生成字符串
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }

    }

    public static boolean ContainsEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return false;
        }

        int len = source.length();

        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);

            if (IsEmojiCharacter(codePoint)) {
                //do nothing，判断到了这里表明，确认有表情字符
                return true;
            }
        }

        return false;
    }

    private static boolean IsEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) ||
                (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }


    public static boolean ValidateEmail(String email){
        //Pattern pattern = Pattern.compile("[0-9a-zA-Z]*.[0-9a-zA-Z]*@[a-zA-Z]*.[a-zA-Z]*", Pattern.LITERAL);
        if(email == null){
            return false;
        }
        //验证开始
        //不能有连续的.
        if(email.indexOf("..") != -1){
            return false;
        }
        //必须带有@
        int atCharacter = email.indexOf("@");
        if (atCharacter == -1) {
            return false;
        }
        //最后一个.必须在@之后,且不能连续出现
        if(atCharacter > email.lastIndexOf('.') || atCharacter+1 == email.lastIndexOf('.')){
            return false;
        }
        //不能以.,@结束和开始
        if (email.endsWith(".") || email.endsWith("@") || email.startsWith(".") || email.startsWith("@")) {
            return false;
        }
        return true;
    }



    public static File DownLoadUrlImg(String path, String fileName) throws IOException {
        URL url = new URL(path);
        java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
        DataInputStream input = new DataInputStream(conn.getInputStream());
        DataOutputStream output = new DataOutputStream(new FileOutputStream(fileName));
        byte[] buffer = new byte[1024 * 8];
        int count = 0;
        while ((count = input.read(buffer)) > 0) {
            output.write(buffer, 0, count);
        }
        output.close();
        input.close();
        return new File(fileName);
    }


    public static HashMap<String, String> StringToMap(String str) {
        if(str.split("\\{").length!=2||str.split("\\{")[1].split("\\}").length!=1){
            return new HashMap<String, String>();
        }
        String[] params = str.split("\\{")[1].split("\\}")[0].split(",");
        HashMap<String,String> hashMap = new HashMap<String, String>();
        for(String param :params){
            String[] splits = param.split("=");
            if(splits.length!=2){
                return new HashMap<String, String>();
            }else{
                hashMap.put(splits[0].trim(),splits[1].trim());
            }
        }
       return hashMap;

    }
}
